﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Effects;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Resources;
using System.Globalization;
using System.Collections.ObjectModel;
using System.IO;
using System.Windows.Threading;
using System.Diagnostics;
using System.ComponentModel;
using System.Net;
using ArmoryData;
using ArmoryData.Character;
using ArmoryViewer.Classes;
using Microsoft.WindowsAPICodePack.Taskbar;
using Microsoft.WindowsAPICodePack.Dialogs;
using Microsoft.WindowsAPICodePack.Shell;


namespace ArmoryViewer
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class MainWindow : GlassWindow
    {
        static ProgressWindow pgs;
        System.Windows.Forms.NotifyIcon ni;
        BackgroundWorker bgwSearch = new BackgroundWorker();
        static bool searchBusy = true;
        ObservableCollection<Dictionary<string, string>> itemSource;


        /// <summary>
        /// Initializes a new instance of the <see cref="MainWindow"/> class.
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();
            AddSortBinding();
            AddNotifyIcon();
#if !DEBUG
            mnuMain.Items.Remove(menuDebug);
#endif
        }

        /// <summary>
        /// Creates the notification icon in the system tray.
        /// </summary>
        void AddNotifyIcon()
        {
            ni = new System.Windows.Forms.NotifyIcon();
            Stream iconStream = Application.GetResourceStream(new Uri("/ArmoryViewer;component/Resources/armoryViewer.ico", UriKind.Relative)).Stream;
            if (iconStream != null)
                ni.Icon = new System.Drawing.Icon(iconStream);
            ni.Visible = true;
            ni.DoubleClick += delegate(object sender, EventArgs e)
            {
                this.Show();
                this.WindowState = WindowState.Normal;
            };
        }

        /// <summary>
        ///  Sets the sorter for the ListView
        /// </summary>
        void AddSortBinding()
        {
            GridView gv = (GridView)lvwResults.View;
            for (int i = 1; i <= gv.Columns.Count; i++)
            {
                GridViewColumn col = gv.Columns[i - 1];
                ListViewSorter.SetSortBindingMember(col, new Binding(lvwResults.Name));
            }
            ListViewSorter.SetCustomSorter(lvwResults, new ResultSorter());
        }

		private void Preferences_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            string curCulture = System.Globalization.CultureInfo.CurrentCulture.ToString();
			PreferencesWindow win = new PreferencesWindow();
			win.ShowDialog();
            if (curCulture != System.Globalization.CultureInfo.CurrentCulture.ToString())
            {
                LocalizationProvider.UpdateAllObjects();
            }
        }
		
        private void Exit_Click(object sender, System.Windows.RoutedEventArgs e)
        {
        	Application.Current.Shutdown();
        }

        private void menuAbout_Click(object sender, RoutedEventArgs e)
        {
            AboutWindow win = new AboutWindow();
            win.Show();
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            FixColumnWidth(ref lvwResults, true);
            AeroGlassCompositionChanged += new AeroGlassCompositionChangedEvent(MainWindow_AeroGlassCompositionChanged);
            if (App.IsVista && AeroGlassCompositionEnabled)
                SetAeroGlassTransparency();
            else
                this.Background = SystemColors.ControlBrush;
        }

        void MainWindow_AeroGlassCompositionChanged(object sender, AeroGlassCompositionChangedEvenArgs e)
        {
            if (App.IsVista && e.GlassAvailable)
            {
                SetAeroGlassTransparency();
                InvalidateVisual();
            }
            else
                this.Background = SystemColors.ControlBrush;
        }
        
        public void Search(string query)
        {
            // Create background worker
            bgwSearch = new BackgroundWorker();
            bgwSearch.WorkerReportsProgress = true;
            bgwSearch.WorkerSupportsCancellation = true;
            bgwSearch.DoWork += new DoWorkEventHandler(bgwSearch_DoWork);
            bgwSearch.ProgressChanged += new ProgressChangedEventHandler(bgwSearch_ProgressChanged);
            bgwSearch.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgwSearch_RunWorkerCompleted);

            // Show the progress window
            pgs = new ProgressWindow()
            {
                Title = App.ResourceManager.GetString("Searching", CultureInfo.CurrentCulture),
                Text = string.Format(App.ResourceManager.GetString("SearchingFor", CultureInfo.CurrentCulture), query),
                ProgressState = TaskDialogProgressBarState.Marquee
            };
            pgs.TaskDialogClosing = delegate(object sender, TaskDialogClosingEventArgs e)
            {
                if (searchBusy)
                {
                    bgwSearch.CancelAsync();
                    pgs.Text = "Cancelling...";
                    e.Cancel = true;
                }
            };
            bgwSearch.RunWorkerAsync(new string[] { cboSearchType.SelectedIndex.ToString(), query });
            pgs.ShowMe();
        }
        
        void FillResults(List<Dictionary<string, string>> results)
        {
            if (itemSource != null)
            {
                lvwResults.Items.SortDescriptions.Clear();
                ListViewSorter.SetCustomSorter(lvwResults, null);
                ListCollectionView view = (ListCollectionView)CollectionViewSource.GetDefaultView(lvwResults.ItemsSource);
                view.CustomSort = null;
            }

            if (results != null)
            {
                itemSource = new ObservableCollection<Dictionary<string, string>>(results);
                lvwResults.ItemsSource = itemSource;
                lvwResults.SelectedItems.Clear();
            }
            ListViewSorter.SetCustomSorter(lvwResults, new ResultSorter());
            FixColumnWidth(ref lvwResults);
            ListViewSorter.SortBy("Level", ListSortDirection.Descending);
        }

        void FixColumnWidth(ref ListView listView, bool first=false)
        {
            GridView view = listView.View as GridView;
            if (view == null) return;

            foreach(GridViewColumn col in view.Columns)
            {
                if (col.Header.ToString() == App.ResourceManager.GetString("Level", CultureInfo.CurrentCulture)) 
                    col.Width = 35;
                else
                {
                    col.Width = col.ActualWidth;
                    col.Width = Double.NaN;
                    if (first) col.Width = col.ActualWidth + 10;
                }
            }
        }

        void bgwSearch_DoWork(object sender, DoWorkEventArgs e)
        {
            searchBusy = true;
            BackgroundWorker bgwSender = (BackgroundWorker)sender;
            string[] args = (string[])e.Argument;
            string query = args[1];
            try
            {
                if (bgwSender.CancellationPending) return;
                switch (int.Parse(args[0]))
                {
                    case 1:
                        e.Result = Connector.GetSearchResults(Settings.ArmoryUrl, query, "characters");
                        break;
                    case 2:
                        e.Result = Connector.GetSearchResults(Settings.ArmoryUrl, query.Replace(" ", "+"), "guilds");
                        break;
                    case 0:
                        e.Result = Connector.GetSearchResults(Settings.ArmoryUrl, query.Replace(" ", "+"), "arenateams");
                        break;
                }
            }
            catch (WebException ex)
            {
                MessageBox.Show(ex.Message);
            }
            catch (Exception ex)
            {
                if (bgwSender.CancellationPending) return;
                bgwSender.ReportProgress(1, ex);
            }
        }

        void bgwSearch_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                searchBusy = false;
                if (pgs == null) return;
                BackgroundWorker bgwSender = (BackgroundWorker)sender;
                if (!bgwSender.CancellationPending) FillResults((List<Dictionary<string, string>>)e.Result);
                bgwSender = new BackgroundWorker();
                pgs.CloseDialog();
            }
            catch (Exception ex)
            {
                App.ShowErrorDialog(ex);
            }
        }

        void bgwSearch_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (e.UserState is Exception)
            {
                pgs.CloseDialog();
                App.ShowErrorDialog(e.UserState as Exception);
            }
        }

        private void menuHelpUpdates_Click(object sender, RoutedEventArgs e)
        {
            App.CheckForUpdates();
        }

        private void MainWindow_Closed(object sender, EventArgs e)
        {
            ni.Visible = false;
            Application.Current.Shutdown();
        }

        private void Error_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                Exception omgException = new Exception("Whoa its an exception, looks like you're testing out the awesome send error report feature.");
                throw omgException;
            }
            catch (Exception ex)
            {
                App.ShowErrorDialog(ex);
            }
        }

        private void MainWindow_StateChanged(object sender, EventArgs e)
        {
            if (Settings.HideWhenMinimized && this.WindowState == WindowState.Minimized)
                Hide();
        }

        private void MainWindow_Closing(object sender, CancelEventArgs e)
        {
            ni.Visible = false;
        }

        void CharacterLoader_LoaderProgressChanged(object sender, LoaderProgressChangedEventArgs e)
        {
            if (e.Message != null)
            {
                // Show error
                if (e.Message == "error")
                {
                    pgs.CurrentValue = 100;
                    pgs.ProgressState = TaskDialogProgressBarState.Error;
                    pgs.Caption = "Load Failed";
                    pgs.Text = e.Error.Message;
                    pgs.StandardButtons = TaskDialogStandardButtons.Close;
                }
                // Show message
                else
                    pgs.Text = e.Message;
            }
        }

        void CharacterLoader_LoaderCompleted(object sender, CharacterInfo c)
        {
            try
            {
                ArmoryViewer.Windows.ProfileWindow profile = new ArmoryViewer.Windows.ProfileWindow();
                profile.Character = c;
                profile.DisplayData();
                profile.Show();
                pgs.CloseDialog();
            }
            catch (Exception ex)
            {
                App.ShowErrorDialog(ex);
            }
        }

        public void LoadCharacter(string name, string realm)
        {
            CharacterLoader.LoaderCompleted -= CharacterLoader_LoaderCompleted;
            CharacterLoader.LoaderProgressChanged -= CharacterLoader_LoaderProgressChanged;

            CharacterLoader.LoaderCompleted += CharacterLoader_LoaderCompleted;
            CharacterLoader.LoaderProgressChanged += CharacterLoader_LoaderProgressChanged;

            pgs = new ProgressWindow()
            {
                Caption = "Loading Character",
                Text = "Determining what to do...",
                ProgressState = TaskDialogProgressBarState.Marquee,
            };

            pgs.TaskDialogClosing = delegate(object sender, TaskDialogClosingEventArgs e)
            {
                e.Cancel = CancelLoading();
            };

            pgs.Closing += delegate(object sender, CancelEventArgs e)
            {
                e.Cancel = CancelLoading();
            };
            CharacterLoader.LoadCharacter(name, realm);
            pgs.ShowMe();
        }

        bool CancelLoading()
        {
            if (pgs.StandardButtons == TaskDialogStandardButtons.Cancel)
            {
                if (MessageBox.Show("Are you sure you wish to cancel loading?", "Armory Viewer", MessageBoxButton.YesNo) == MessageBoxResult.No)
                    return true;
                else
                    CharacterLoader.Cancel();
            }
            return false;
        }

        private void lvwResults_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            LoadCharacter();
        }

        private void LoadCharacter_Click(object sender, RoutedEventArgs e)
        {
            LoadCharacter();
        }

        void LoadCharacter()
        {
            if (lvwResults.SelectedItem == null) return;
            Dictionary<string, string> charData = (Dictionary<string, string>)lvwResults.SelectedItem;
            string name = charData["Name"];
            string realm = charData["Realm"];
            LoadCharacter(name, realm);
        }

        private void btnMenu_Click(object sender, RoutedEventArgs e)
        {
            mnuMain.PlacementTarget = this;
            mnuMain.IsOpen = true;
        }

        private void txtQuery_Search(object sender, RoutedEventArgs e)
        {
            if (bgwSearch.IsBusy) return; // Don't try to search if already searching

            // If there's no text to search for then reset the list.
            if (txtQuery.Text == "")
            {
                lvwResults.ItemsSource = new List<Dictionary<string, string>>();
                return;
            }

            Search(txtQuery.Text);
        }

        private void menuForceUpdate_Click(object sender, RoutedEventArgs e)
        {
            App.CheckForUpdates(true);
        }
    }
}
